import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './index.css';
// import { connect } from "dva";

const doc = document;
const win = window;

const getStyle = (ele, name) => {
    return win.getComputedStyle ? win.getComputedStyle(ele, name || null) : ele.currentStyle;
}

class SelectArea extends Component {
    constructor(props) {
        super(props);
        this.state = {
            el: null,
            container: null,
            selectArea: {
                max: true, //是否设置范围限制(为true时下面mx参数有用)
                top: 0, //上边限制
                left: 0, //左边限制
                right: 9999, //右边限制
                bottom: 9999, //下边限制
                min: true, //是否最小宽高限制(为true时下面min参数有用)
                minWidth: 50,//最小宽度
                minHeight: 50,//最小高度

                ratio: 0, //缩放比例(宽/高)
                scale: false, //是否按比例缩放

                lockX: false,//是否锁定水平方向拖放
                lockY: false,//是否锁定垂直方向拖放
                lock: false,//是否锁定
            }
        }

        this.moveResize = this.moveResize.bind(this);
        this.stopResize = this.stopResize.bind(this);
        this.moveDrag = this.moveDrag.bind(this);
        this.stopDrag = this.stopDrag.bind(this);

    }
    componentDidMount() {
        const { selectArea } = this.state;
        const el = this._selectAreaEl;
        const container = el.parentElement;

        const { props } = this;
        let width = props.width || 50;
        let height = props.height || 50;
        let left = props.left || 0;
        let top = props.top || 0;

        //记录鼠标相对拖放对象的位置
        this._dragX = 0;
        this._dragY = 0;
        this._moveX = 0;
        this._moveY = 0;
        //记录margin
        this._marginLeft = parseInt(getStyle(el)['margin-left']) || 0;
        this._marginTop = parseInt(getStyle(el)['margin-top']) || 0;

        //样式参数
        this._styleTop = width;
        this._styleLeft = height;
        this._styleWidth = left;
        this._styleHeight = top;

        //定位参数
        this._fixLeft = left + width;
        this._fixTop = top + height;

        //坐标参数
        this._sideLeft = 0;
        this._sideRight = 0;
        this._sideUp = 0;
        this._sideDown = 0;

        //定位坐标
        this._scaleLeft = 0;
        this._scaleTop = 0;

        //比例范围参数
        this._scaleWidth = 0;
        this._scaleHeight = 0;


        this._upHeight = 0;
        this._rightWidth = 0;
        this._downHeight = 0;
        this._leftWidth = 0;

        this._borderX = (parseInt(getStyle(el)['border-left-width']) || 0) + (parseInt(getStyle(el)['border-right-width']) || 0);
        this._borderY = (parseInt(getStyle(el)['border-top-width']) || 0) + (parseInt(getStyle(el)['border-bottom-width']) || 0);

        let mxLeft, mxRight, mxTop, mxBottom,
            iLeft = left,
            iTop = top;

        //设置范围限制
        //防止初始化的时候超出边界
        if(selectArea.max) {
            //设置范围参数
            mxLeft = selectArea.left;
            mxRight = selectArea.right;
            mxTop = selectArea.top;
            mxBottom = selectArea.bottom;

            //如果设置了容器，再修正范围参数
            if (container) {
                mxLeft = Math.max(mxLeft, 0);
                mxTop = Math.max(mxTop, 0);
                mxRight = Math.min(mxRight, parseInt(getStyle(container)['width']) || container.clientWidth);
                mxBottom = Math.min(mxBottom, parseInt(getStyle(container)['height']) || container.clientHeight);
            }
            //修正移动参数
            iLeft = Math.max(Math.min(iLeft, mxRight - (width + this._borderX)), mxLeft);
            iTop = Math.max(Math.min(iTop, mxBottom - (height + this._borderY)), mxTop);

            if(!selectArea.lockX){
                left = iLeft - this._marginLeft;
            }
            if(!selectArea.lockY){
                top = iTop - this._marginTop;
            }
        }

        el.style.width = width + 'px';
        el.style.height = height + 'px';
        el.style.left = left + 'px';
        el.style.top = top + 'px';
        container.style.cursor = "default";

        this._mxSet = () => {};//范围设置程序
        this._fun = () => {};//缩放执行程序

        this.setState({
            el,
            container
        });
    }
    componentWillUnmount() {
        this.stopDrag();
        this.stopResize();
    }
    setCursor(type){
        const { container } = this.state;

        console.log(type);
        if(!this._isDrag) {
            container.style.cursor = type || 'default';
        }
    }
    drag(e){
        const { props } = this;
        const { selectArea, el }  = this.state;

        if(selectArea.lock || e.button != 0){
            delete this._isDrag;
            return;
        }

        this._isDrag = true;
        this._repair();

        this._dragX = e.pageX - el.offsetLeft;
        this._dragY = e.pageY - el.offsetTop;
        this._moveX = e.pageX;
        this._moveY = e.pageY;
        this._startDate = (new Date).getTime();

        //记录margin
        this._marginLeft = parseInt(getStyle(el)['margin-left']) || 0;
        this._marginTop = parseInt(getStyle(el)['margin-top']) || 0;

        //mousemove时移动
        doc.addEventListener('mousemove', this.moveDrag, false);
        doc.addEventListener('mouseup', this.stopDrag, false);
        win.addEventListener('blur', this.stopDrag, false);

        props.onStartDrag && props.onStartDrag(e);
    }
    moveDrag(e){
        const { props } = this;
        const { selectArea, container, el } = this.state;
        if(selectArea.lock){
            this.stopDrag(e);
            return;
        }

        let iLeft, iTop, mxLeft, mxRight, mxTop, mxBottom;

        //清除选择
        e.preventDefault();
        win.getSelection ? win.getSelection().removeAllRanges() : doc.selection.empty();

        iLeft = e.pageX - this._dragX;
        iTop = e.pageY - this._dragY;

        e.moveX = e.pageX - this._moveX;
        e.moveY = e.pageY - this._moveY;

        //设置范围限制
        if(selectArea.max){
            //设置范围参数
            mxLeft = selectArea.left;
            mxRight = selectArea.right;
            mxTop = selectArea.top;
            mxBottom = selectArea.bottom;

            //如果设置了容器，再修正范围参数
            if(container){
                mxLeft = Math.max(mxLeft, 0);
                mxTop = Math.max(mxTop, 0);
                mxRight = Math.min(mxRight, parseInt(getStyle(container)['width']) || container.clientWidth);
                mxBottom = Math.min(mxBottom, parseInt(getStyle(container)['height']) || container.clientHeight);
            }

            //修正移动参数
            iLeft = Math.max(Math.min(iLeft, mxRight - (el.offsetWidth + this._borderX)), mxLeft);
            iTop = Math.max(Math.min(iTop, mxBottom - (el.offsetHeight + this._borderY)), mxTop);
        }

        let dragX = el.offsetLeft;
        let dragY = el.offsetTop;

        if(!selectArea.lockX){
            dragX = iLeft - this._marginLeft;
        }
        if(!selectArea.lockY){
            dragY = iTop - this._marginTop;
        }

        el.style.left = dragX + 'px';
        el.style.top = dragY + 'px';

        e.dragX = dragX;
        e.dragY = dragY;

        //附加程序
        props.onDrag && props.onDrag(e);
    }
    stopDrag(e){
        const { props } = this;

        doc.removeEventListener('mousemove', this.moveDrag);
        doc.removeEventListener('mouseup', this.stopDrag);
        win.removeEventListener('blur', this.stopDrag);

        if(e) {
            if (props.onClick) {
                const endDate = (new Date).getTime();
                const isClick = endDate - this._startDate < 300;
                if (isClick) {
                    props.onClick(e);
                }
            }
            props.onEndDrag && props.onEndDrag(e);
        }

        delete this._isDrag;
        delete this._startDate;
    }

    //修正范围
    _repair() {
        const { selectArea, el } = this.state;
        if(selectArea.max){
            //修正错误范围参数
            this.setState({
                selectArea: Object.assign(selectArea, {
                    right: Math.max(selectArea.right, selectArea.left + el.offsetWidth + this._borderX),
                    bottom: Math.max(selectArea.bottom, selectArea.top + el.offsetHeight + this._borderY)
                })
            })
        }
    }
    resize(e, fun){

        const { props, state } = this;
        const { el, selectArea, container } = state;

        e.stopPropagation();
        this._fun = fun;

        this._isDrag = true;

        //样式参数值
        this._styleLeft = el.offsetLeft;
        this._styleTop = el.offsetTop;
        this._styleWidth = parseInt(getStyle(el)['width']) || el.clientWidth;
        this._styleHeight = parseInt(getStyle(el)['height']) || el.clientHeight;
        //四条边定位坐标
        this._sideLeft = e.pageX - this._styleWidth;
        this._sideRight = e.pageX + this._styleWidth;
        this._sideUp = e.pageY - this._styleHeight;
        this._sideDown = e.pageY + this._styleHeight;

        //top和left定位参数
        this._fixLeft = this._styleLeft + this._styleWidth;
        this._fixTop = this._styleTop + this._styleHeight;

        const newSelectArea = {};

        if(selectArea.scale){
            //设置比例
            newSelectArea.ratio = Math.max(selectArea.ratio, 0) || this._styleWidth / this._styleHeight;

            //left和top的定位坐标
            this._scaleLeft = this._styleLeft + this._styleWidth / 2;
            this._scaleTop = this._styleTop + this._styleHeight / 2;
        }

        if(selectArea.max){
            //设置范围参数
            let mxLeft = selectArea.left,
                mxRight = selectArea.right,
                mxTop = selectArea.top,
                mxBottom = selectArea.bottom;

            if(container){
                mxLeft = Math.max(mxLeft, 0);
                mxTop = Math.max(mxTop, 0);
                mxRight = Math.min(mxRight, parseInt(getStyle(container)['width']) || container.clientWidth);
                mxBottom = Math.min(mxBottom, parseInt(getStyle(container)['height']) || container.clientHeight);
            }

            //根据最小值再修正
            mxRight = Math.max(mxRight, mxLeft + (selectArea.min ? selectArea.minWidth : 0) + this._borderX);
            mxBottom = Math.max(mxBottom, mxTop + (selectArea.min ? selectArea.minHeight : 0) + this._borderY);

            //由于转向时要重新设置所以写成function形式
            this._mxSet = () => {
                this._rightWidth = mxRight - this._styleLeft - this._borderX;
                this._downHeight = mxBottom - this._styleTop - this._borderY;
                this._upHeight = Math.max(this._fixTop - mxTop, selectArea.min ? selectArea.minHeight : 0);
                this._leftWidth = Math.max(this._fixLeft - mxLeft, selectArea.min ? selectArea.minWidth : 0);
            };
            this._mxSet();

            //有缩放比例下的范围限制
            if(selectArea.scale){
                this._scaleWidth = Math.min(this._scaleLeft - mxLeft, mxRight - this._scaleLeft - this._borderX) * 2;
                this._scaleHeight = Math.min(this._scaleTop - mxTop, mxBottom - this._scaleTop - this._borderY) * 2;
            }
        }

        this.setState({
            selectArea: Object.assign(selectArea, newSelectArea)
        });

        doc.addEventListener('mousemove', this.moveResize, false);
        doc.addEventListener('mouseup', this.stopResize, false);
        win.addEventListener('blur', this.stopResize, false);

        props.onStartResize && props.onStartResize(e);
    }
    moveResize(e){
        const { props } = this;
        const { el } = this.state;
        win.getSelection ? win.getSelection().removeAllRanges() : doc.selection.empty();

        this._fun(e);

        el.style.width = this._styleWidth + 'px';
        el.style.height = this._styleHeight + 'px';
        el.style.left = this._styleLeft + 'px';
        el.style.top = this._styleTop + 'px';

        props.onResize && props.onResize(e);
    }
    stopResize(e){
        const { props } = this;

        doc.removeEventListener('mousemove', this.moveResize);
        doc.removeEventListener('mouseup', this.stopResize);
        win.removeEventListener('blur', this.stopResize);
        delete this._func;
        delete this._mxSet;
        delete this._isDrag;

        if(e) {
            props.onEndResize && props.onEndResize(e);
        }
    }
    //上
    setUp(e){
        this._repairY(this._sideDown - e.pageY, this._upHeight);
        this._repairTop();
        this._turnDown(this.setDown);
    }
    //下
    setDown(e) {
        this._repairY(e.pageY - this._sideUp, this._downHeight);
        this._turnUp(this.setUp);
    }
    //右
    setRight(e){
        this._repairX(e.pageX - this._sideLeft, this._rightWidth);
        this._turnLeft(this.setLeft);
    }
    //左
    setLeft(e){
        this._repairX(this._sideRight - e.pageX, this._leftWidth);
        this._repairLeft();
        this._turnRight(this.setRight);
    }
    //右下
    setRightDown(e) {
        const { selectArea } = this.state;
        this._repairAngle(
            e.pageX - this._sideLeft, this._rightWidth,
            e.pageY - this._sideUp, this._downHeight
        );
        this._turnLeft(this.setLeftDown) || selectArea.scale || this._turnUp(this.setRightUp);
    }
    //右上
    setRightUp(e) {
        const { selectArea } = this.state;
        this._repairAngle(
            e.pageX - this._sideLeft, this._rightWidth,
            this._sideDown - e.pageY, this._upHeight
        );
        this._repairTop();
        this._turnLeft(this.setLeftUp) || selectArea.scale || this._turnDown(this.setRightDown);
    }
    //左下
    setLeftDown(e) {
        const { selectArea } = this.state;
        this._repairAngle(
            this._sideRight - e.pageX, this._leftWidth,
            e.pageY - this._sideUp, this._downHeight
        );
        this._repairLeft();
        this._turnRight(this.setRightDown) || selectArea.scale || this._turnUp(this.setLeftUp);
    }
    //左上
    setLeftUp(e) {
        const { selectArea } = this.state;
        this._repairAngle(
            this._sideRight - e.pageX, this._leftWidth,
            this._sideDown - e.pageY, this._upHeight
        );
        this._repairTop();
        this._repairLeft();
        this._turnRight(this.setRightUp) || selectArea.scale || this._turnDown(this.setLeftDown);
    }

    //修正程序
    //水平方向
    _repairX(iWidth, mxWidth) {
        const { selectArea } = this.state;
        iWidth = this._repairWidth(iWidth, mxWidth);
        if(selectArea.scale){
            let iHeight = this._repairScaleHeight(iWidth);
            if(selectArea.max && iHeight > this._scaleHeight){
                iHeight = this._scaleHeight;
                iWidth = this._repairScaleWidth(iHeight);
            } else if(selectArea.min && iHeight < selectArea.minHeight){
                let tWidth = this._repairScaleWidth(selectArea.minHeight);
                if(tWidth < mxWidth){
                    iHeight = selectArea.minHeight;
                    iWidth = tWidth;
                }
            }
            this._styleHeight = iHeight;
            this._styleTop = this._scaleTop - iHeight / 2;
        }
        this._styleWidth = iWidth;
    }
    //垂直方向
    _repairY(iHeight, mxHeight) {
        const { selectArea } = this.state;
        iHeight = this._repairHeight(iHeight, mxHeight);
        if(selectArea.scale){
            let iWidth = this._repairScaleWidth(iHeight);
            if(selectArea.max && iWidth > this._scaleWidth){
                iWidth = this._scaleWidth;
                iHeight = this._repairScaleHeight(iWidth);
            } else if(selectArea.min && iWidth < selectArea.minWidth){
                let tHeight = this._repairScaleHeight(selectArea.minWidth);
                if(tHeight < mxHeight){
                    iWidth = selectArea.minWidth;
                    iHeight = tHeight;
                }
            }

            this._styleWidth = iWidth;
            this._styleLeft = this._scaleLeft - iWidth / 2;
        }

        this._styleHeight = iHeight;
    }
    //top
    _repairTop() {
        this._styleTop = this._fixTop - this._styleHeight;
    }
    //left
    _repairLeft() {
        this._styleLeft = this._fixLeft - this._styleWidth;
    }
    //width
    _repairWidth(iWidth, mxWidth) {
        const { selectArea } = this.state;
        iWidth = Math.min(selectArea.max ? mxWidth : iWidth, iWidth);
        iWidth = Math.max(selectArea.min ? selectArea.minWidth : iWidth, iWidth, 0);
        return iWidth;
    }
    //height
    _repairHeight(iHeight, mxHeight) {
        const { selectArea } = this.state;
        iHeight = Math.min(selectArea.max ? mxHeight : iHeight, iHeight);
        iHeight = Math.max(selectArea.min ? selectArea.minHeight : iHeight, iHeight, 0);
        return iHeight;
    }
    //比例高度
    _repairScaleHeight(iWidth) {
        const { selectArea } = this.state;
        return Math.max(Math.round((iWidth + this._borderX) / selectArea.ratio - this._borderY), 0);
    }
    //比例宽度
    _repairScaleWidth(iHeight) {
        const { selectArea } = this.state;
        return Math.max(Math.round((iHeight + this._borderY) * selectArea.ratio - this._borderX), 0);
    }
    //转向程序
    //转右
    _turnRight(fun) {
        const { selectArea } = this.state;
        if(!(selectArea.min || this._styleWidth)){
            this._fun = fun;
            this._sideLeft = this._sideRight;
            selectArea.max && this._mxSet();
            return true;
        }
    }
    //转左
    _turnLeft(fun) {
        const { selectArea } = this.state;
        if(!(selectArea.min || this._styleWidth)){
            this._fun = fun;
            this._sideRight = this._sideLeft;
            this._fixLeft = this._styleLeft;
            selectArea.max && this._mxSet();
            return true;
        }
    }
    //转上
    _turnUp(fun) {
        const { selectArea } = this.state;
        if(!(selectArea.min || this._styleHeight)){
            this._fun = fun;
            this._sideDown = this._sideUp;
            this._fixTop = this._styleTop;
            selectArea.max && this._mxSet();
            return true;
        }
    }
    //转下
    _turnDown(fun) {
        const { selectArea } = this.state;
        if(!(selectArea.min || this._styleHeight)){
            this._fun = fun;
            this._sideUp = this._sideDown;
            selectArea.max && this._mxSet();
            return true;
        }
    }
    //对角方向
    _repairAngle(iWidth, mxWidth, iHeight, mxHeight) {
        const { selectArea } = this.state;
        iWidth = this._repairWidth(iWidth, mxWidth);
        if(selectArea.scale){
            iHeight = this._repairScaleHeight(iWidth);
            if(selectArea.max && iHeight > mxHeight){
                iHeight = mxHeight;
                iWidth = this._repairScaleWidth(iHeight);
            } else if(selectArea.min && iHeight < selectArea.minHeight){
                var tWidth = this._repairScaleWidth(selectArea.minHeight);
                if(tWidth < mxWidth){
                    iHeight = selectArea.minHeight;
                    iWidth = tWidth;
                }
            }
        } else {
            iHeight = this._repairHeight(iHeight, mxHeight);
        }
        this._styleWidth = iWidth;
        this._styleHeight = iHeight;
    }
    render(){
        return (
            <div ref={(el) => {this._selectAreaEl = el}} className="select-area"
                onMouseDown={e => {this.drag(e)}}
            >
                <div className="top-resize"
                     onMouseDown={e => {this.resize(e, this.setUp)}}
                     onMouseEnter={() => {this.setCursor('n-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="right-resize"
                     onMouseDown={e => {this.resize(e, this.setRight)}}
                     onMouseEnter={() => {this.setCursor('e-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="bottom-resize"
                     onMouseDown={e => {this.resize(e, this.setDown)}}
                     onMouseEnter={() => {this.setCursor('s-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="left-resize"
                     onMouseDown={e => {this.resize(e, this.setLeft)}}
                     onMouseEnter={() => {this.setCursor('w-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="right-top-resize"
                     onMouseDown={e => {this.resize(e, this.setRightUp)}}
                     onMouseEnter={() => {this.setCursor('ne-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="right-bottom-resize"
                     onMouseDown={e => {this.resize(e, this.setRightDown)}}
                     onMouseEnter={() => {this.setCursor('se-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="left-top-resize"
                     onMouseDown={e => {this.resize(e, this.setLeftUp)}}
                     onMouseEnter={() => {this.setCursor('nw-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                <div className="left-bottom-resize"
                     onMouseDown={e => {this.resize(e, this.setLeftDown)}}
                     onMouseEnter={() => {this.setCursor('sw-resize')}}
                     onMouseLeave={() => {this.setCursor()}}
                ></div>
                {this.props.children}

            </div>
        );
    }
}

SelectArea.propTypes = {
    children: PropTypes.element
};
SelectArea.defaultProps = {
    children: null
};

class Container extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return (
            <div className="pdf-container">
                <SelectArea width={200} height={100} left={100} top={100} onClick={(e) => {
                    console.log(e);
                }} >
                </SelectArea>
                <SelectArea width={200} height={100} left={0} top={300} >
                    <input />
                </SelectArea>
            </div>
        );
    }
}


export default Container;